"""
@Author: li
@Email: lijianqiao2906@live.com
@FileName: base.py
@DateTime: 2025/07/05
@Docs: 基础DAO层，提供高性能的CRUD操作
"""

import asyncio
from typing import Any

from tortoise.exceptions import DoesNotExist
from tortoise.models import Model
from tortoise.queryset import QuerySet
from tortoise.transactions import in_transaction

from app.utils.logger import logger


class BaseDAO:
    """基础DAO类，提供高性能的数据库操作"""

    def __init__(self, model: type[Model]):
        self.model = model

    async def get_by_id(self, id: int) -> Model | None:
        """根据ID获取单个对象"""
        try:
            return await self.model.get_or_none(id=id)
        except Exception as e:
            logger.error(f"获取对象失败: {e}")
            return None

    async def get_by_ids(self, ids: list[int], order_by: list[str] | None = None) -> list[Model]:
        """根据ID列表批量获取对象，并支持排序"""
        if order_by is None:
            order_by = ["-id"]
        return await self.model.filter(id__in=ids).order_by(*order_by)

    async def get_one(self, **filters) -> Model | None:
        """根据条件获取单个对象"""
        try:
            return await self.model.filter(**filters).first()
        except Exception as e:
            logger.error(f"获取单个对象失败: {e}")
            return None

    async def get_all(self, **filters) -> list[Model]:
        """获取所有对象"""
        try:
            return await self.model.filter(**filters).all()
        except Exception as e:
            logger.error(f"获取对象列表失败: {e}")
            return []

    async def exists(self, **filters) -> bool:
        """检查对象是否存在"""
        try:
            return await self.model.filter(**filters).exists()
        except Exception as e:
            logger.error(f"检查对象存在性失败: {e}")
            return False

    async def count(self, **filters) -> int:
        """获取对象数量"""
        try:
            return await self.model.filter(**filters).count()
        except Exception as e:
            logger.error(f"获取对象数量失败: {e}")
            return 0

    async def create(self, **data) -> Model | None:
        """创建单个对象"""
        try:
            return await self.model.create(**data)
        except Exception as e:
            logger.error(f"创建对象失败: {e}")
            return None

    async def bulk_create(self, objects_data: list[dict[str, Any]]) -> list[Model]:
        """批量创建对象（高性能）"""
        try:
            objects = [self.model(**data) for data in objects_data]
            result = await self.model.bulk_create(objects)
            return result or []
        except Exception as e:
            logger.error(f"批量创建对象失败: {e}")
            return []

    async def update_by_id(self, id: int, **data) -> Model | None:
        """根据ID更新对象"""
        try:
            obj = await self.get_by_id(id)
            if obj:
                await obj.update_from_dict(data).save()
                return obj
            return None
        except Exception as e:
            logger.error(f"更新对象失败: {e}")
            return None

    async def bulk_update(self, updates: list[dict[str, Any]], id_field: str = "id") -> int:
        """批量更新对象（高性能）"""
        try:
            update_count = 0
            async with in_transaction():
                for update_data in updates:
                    if id_field not in update_data:
                        continue

                    obj_id = update_data.pop(id_field)
                    count = await self.model.filter(id=obj_id).update(**update_data)
                    update_count += count

            return update_count
        except Exception as e:
            logger.error(f"批量更新对象失败: {e}")
            return 0

    async def update_by_filter(self, filters: dict[str, Any], **data) -> int:
        """根据条件批量更新"""
        try:
            return await self.model.filter(**filters).update(**data)
        except Exception as e:
            logger.error(f"条件更新失败: {e}")
            return 0

    async def delete_by_id(self, id: int) -> bool:
        """根据ID删除对象（默认软删除）"""
        return await self.soft_delete_by_id(id)

    async def delete_by_ids(self, ids: list[int]) -> int:
        """根据ID列表批量删除（默认软删除）"""
        return await self.soft_delete_by_ids(ids)

    async def delete_by_filter(self, **filters) -> int:
        """根据条件批量删除（默认软删除）"""
        return await self.soft_delete_by_filter(**filters)

    async def get_paginated(
        self, page: int = 1, page_size: int = 10, order_by: list[str] | None = None, **filters
    ) -> tuple[list[Model], int]:
        """分页获取对象（高性能）"""
        try:
            # 计算偏移量
            offset = (page - 1) * page_size

            # 构建查询
            queryset = self.model.filter(**filters)

            # 添加排序
            if order_by:
                queryset = queryset.order_by(*order_by)

            # 同时执行计数和分页查询（并行执行提高性能）
            total_task = queryset.count()
            objects_task = queryset.offset(offset).limit(page_size).all()

            total, objects = await asyncio.gather(total_task, objects_task)

            return objects, total
        except Exception as e:
            logger.error(f"分页获取对象失败: {e}")
            return [], 0

    def get_queryset(self, **filters) -> QuerySet[Model]:
        """获取查询集，用于复杂查询"""
        return self.model.filter(**filters)

    async def bulk_upsert(
        self, objects_data: list[dict[str, Any]], conflict_fields: list[str], update_fields: list[str] | None = None
    ) -> list[Model]:
        """批量插入或更新（UPSERT操作）"""
        try:
            # 如果没有指定更新字段，则更新除冲突字段外的所有字段
            if update_fields is None:
                if objects_data:
                    update_fields = [key for key in objects_data[0].keys() if key not in conflict_fields]
                else:
                    update_fields = []

            objects = [self.model(**data) for data in objects_data]
            result = await self.model.bulk_create(objects, on_conflict=conflict_fields, update_fields=update_fields)
            return result or []
        except Exception as e:
            logger.error(f"批量UPSERT失败: {e}")
            return []

    async def update_or_create(self, defaults: dict[str, Any] | None = None, **kwargs) -> tuple[Model, bool]:
        """更新或创建对象 (UPSERT)"""
        try:
            return await self.model.update_or_create(defaults=defaults, **kwargs)
        except Exception as e:
            logger.error(f"更新或创建对象失败: {e}")
            # 在某些情况下，可能需要根据具体错误进行更精细的处理
            # 例如，如果是因为并发问题，可以尝试重试
            # 这里为了通用性，直接向上抛出异常
            raise

    async def get_or_create(self, defaults: dict[str, Any] | None = None, **kwargs) -> tuple[Model, bool]:
        """获取或创建对象"""
        try:
            return await self.model.get_or_create(defaults=defaults, **kwargs)
        except Exception as e:
            logger.error(f"获取或创建对象失败: {e}")
            # 返回默认值 - 创建一个新对象
            if defaults:
                data = {**kwargs, **defaults}
            else:
                data = kwargs
            obj = self.model(**data)
            return obj, True

    # 软删除方法
    async def soft_delete_by_id(self, id: int) -> bool:
        """根据ID软删除对象（标记为已删除）"""
        try:
            count = await self.model.filter(id=id, is_deleted=False).update(is_deleted=True)
            return count > 0
        except Exception as e:
            logger.error(f"软删除对象失败: {e}")
            return False

    async def soft_delete_by_ids(self, ids: list[int]) -> int:
        """根据ID列表批量软删除"""
        try:
            return await self.model.filter(id__in=ids, is_deleted=False).update(is_deleted=True)
        except Exception as e:
            logger.error(f"批量软删除对象失败: {e}")
            return 0

    async def soft_delete_by_filter(self, **filters) -> int:
        """根据条件批量软删除"""
        try:
            # 添加is_deleted=False条件，避免重复软删除
            filters["is_deleted"] = False
            return await self.model.filter(**filters).update(is_deleted=True)
        except Exception as e:
            logger.error(f"条件软删除失败: {e}")
            return 0

    # 硬删除方法（物理删除）
    async def hard_delete_by_id(self, id: int) -> bool:
        """根据ID硬删除对象（物理删除）"""
        try:
            obj = await self.get_by_id(id)
            if obj:
                await obj.delete()
                return True
            return False
        except Exception as e:
            logger.error(f"硬删除对象失败: {e}")
            return False

    async def hard_delete_by_ids(self, ids: list[int]) -> int:
        """根据ID列表批量硬删除"""
        try:
            return await self.model.filter(id__in=ids).delete()
        except Exception as e:
            logger.error(f"批量硬删除对象失败: {e}")
            return 0

    async def hard_delete_by_filter(self, **filters) -> int:
        """根据条件批量硬删除"""
        try:
            return await self.model.filter(**filters).delete()
        except Exception as e:
            logger.error(f"条件硬删除失败: {e}")
            return 0

    # 恢复软删除的对象
    async def restore_by_id(self, id: int) -> bool:
        """恢复软删除的对象"""
        try:
            count = await self.model.filter(id=id, is_deleted=True).update(is_deleted=False)
            return count > 0
        except Exception as e:
            logger.error(f"恢复对象失败: {e}")
            return False

    async def restore_by_ids(self, ids: list[int]) -> int:
        """批量恢复软删除的对象"""
        try:
            return await self.model.filter(id__in=ids, is_deleted=True).update(is_deleted=False)
        except Exception as e:
            logger.error(f"批量恢复对象失败: {e}")
            return 0

    # 查询方法增强（默认排除已软删除的数据）
    async def get_active_by_id(self, id: int) -> Model | None:
        """根据ID获取未删除的对象"""
        try:
            return await self.model.get_or_none(id=id, is_deleted=False)
        except Exception as e:
            logger.error(f"获取未删除对象失败: {e}")
            return None

    async def get_active_all(self, **filters) -> list[Model]:
        """获取所有未删除的对象"""
        try:
            filters["is_deleted"] = False
            return await self.model.filter(**filters).all()
        except Exception as e:
            logger.error(f"获取未删除对象列表失败: {e}")
            return []

    async def get_deleted_all(self, **filters) -> list[Model]:
        """获取所有已软删除的对象"""
        try:
            filters["is_deleted"] = True
            return await self.model.filter(**filters).all()
        except Exception as e:
            logger.error(f"获取已删除对象列表失败: {e}")
            return []

    async def count_active(self, **filters) -> int:
        """统计未删除对象的数量"""
        try:
            filters["is_deleted"] = False
            return await self.model.filter(**filters).count()
        except Exception as e:
            logger.error(f"统计未删除对象数量失败: {e}")
            return 0

    async def count_deleted(self, **filters) -> int:
        """统计已软删除对象的数量"""
        try:
            filters["is_deleted"] = True
            return await self.model.filter(**filters).count()
        except Exception as e:
            logger.error(f"统计已删除对象数量失败: {e}")
            return 0

    async def get_active_paginated(
        self, page: int = 1, page_size: int = 10, order_by: list[str] | None = None, **filters
    ) -> tuple[list[Model], int]:
        """分页获取未删除的对象"""
        try:
            # 添加is_deleted=False条件
            filters["is_deleted"] = False
            return await self.get_paginated(page, page_size, order_by, **filters)
        except Exception as e:
            logger.error(f"分页获取未删除对象失败: {e}")
            return [], 0

    async def paginate(
        self, queryset, page: int = 1, page_size: int = 20, order_by: list[str] | None = None
    ) -> dict[str, Any]:
        """分页查询并返回字典格式结果"""
        try:
            # 添加排序
            if order_by:
                queryset = queryset.order_by(*order_by)
            else:
                queryset = queryset.order_by("-created_at")

            # 计算总数
            total = await queryset.count()

            # 计算偏移量
            offset = (page - 1) * page_size

            # 获取分页数据
            items = await queryset.offset(offset).limit(page_size).all()

            return {
                "items": items,
                "total": total,
                "page": page,
                "page_size": page_size,
                "total_pages": (total + page_size - 1) // page_size,
            }
        except Exception as e:
            logger.error(f"分页查询失败: {e}")
            return {
                "items": [],
                "total": 0,
                "page": page,
                "page_size": page_size,
                "total_pages": 0,
            }

    async def get_by_id_with_prefetch(self, id: int, *prefetch_related: str) -> Model | None:
        """根据ID获取单个对象，并预加载关联数据"""
        try:
            return await self.model.get(id=id).prefetch_related(*prefetch_related)
        except DoesNotExist:
            return None
